package pwd.allen.aio;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 演示AIO通信，单Proactor单线程
 *
 * 特点：底层是IO多路复用，用一个线程就能监控通信，异步I/O
 *
 * @author 门那粒沙
 * @create 2022-03-27 23:33
 **/
public class Server {

    //编码解码的字符集
    private Charset charset = Charset.forName("UTF-8");

    /**
     * 启动服务端测试
     *
     * 用cmd测试
     * telnet localhost 8000        //连接到8000端口
     * ctrl + ]                     //进入telnet命令界面
     * >sen hello world             //输出"hello world"
     * >c                           //关闭连接
     * >q                           //退出
     *
     * @throws IOException
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        final AsynchronousServerSocketChannel channel = AsynchronousServerSocketChannel
                .open()
                .bind(new InetSocketAddress("0.0.0.0",8888));

        HashMap<String, Object> map_attach4Channel = new HashMap<>();
        map_attach4Channel.put("address", channel.getLocalAddress());

        channel.accept(map_attach4Channel, new CompletionHandler<AsynchronousSocketChannel, Map<String, Object>>() {
            @Override
            public void completed(final AsynchronousSocketChannel client, Map<String, Object> attachment) {
                try {
                    System.out.println(String.format("服务端接收到连接：%s", client.getRemoteAddress()));
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // 这里去掉后就无法接收下一个请求了
                channel.accept(null, this);

                ByteBuffer buffer = ByteBuffer.allocate(10);
                Map<String, Object> map_attach4Client = new HashMap<>();
                try {
                    map_attach4Client.put("address", client.getRemoteAddress());
                } catch (IOException e) {}

                client.read(buffer, map_attach4Client, new CompletionHandler<Integer, Map<String, Object>>() {
                    @Override
                    public void completed(Integer result_num, Map<String, Object> attachment) {
                        // 如果连接断开，result_num会返回-1
                        if (result_num == -1) {
                            try {
                                System.out.println(String.format("与%s的连接中断，isopen：%s", client.getRemoteAddress(), client.isOpen()));
                                client.close(); // 这里不知道有没有必要去调用
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            return;
                        } else if (result_num == 0) {
                            return;
                        }

                        //<editor-fold desc="读取数据">
                        buffer.flip();
                        byte[] bytes = new byte[result_num];
                        buffer.get(bytes);
                        buffer.clear();
                        String data = new String(bytes);
                        System.out.println("read data:" + data);
                        //</editor-fold>

                        if ("close".equals(data)) {
                            //<editor-fold desc="主动关闭与客户端的连接">
                            try{
                                client.close();
                                return;
                            }catch (Exception e){}
                            //</editor-fold>
                        } else if ("write".equals(data)) {
                            client.write(ByteBuffer.wrap("this is server".getBytes()));
                        }

                        // 继续读数据
                        client.read(buffer, attachment, this);
                    }

                    @Override
                    public void failed(Throwable exc, Map<String, Object> attachment) {
                        System.out.println("read error：" + exc.toString());
                    }
                });
            }

            @Override
            public void failed(Throwable exc, Map<String, Object> attachment) {
                System.out.println("accept error：" + exc.toString());
            }
        });

        System.out.println("aio服务器启动成功！");
        while (true){
            Thread.sleep(1000);
        }
    }
}
